package com.jl15988.chainlog.manual;

import com.jl15988.chainlog.callback.ChainMethodCallback;
import com.jl15988.chainlog.config.ChainLogProperties;
import com.jl15988.chainlog.context.ChainLogContext;
import com.jl15988.chainlog.model.ChainApiLog;
import com.jl15988.chainlog.model.ChainMethodLog;
import com.jl15988.chainlog.util.ExceptionUtil;
import com.jl15988.chainlog.util.IdUtil;
import com.jl15988.chainlog.util.ReflectionUtil;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 统一监控工具类
 * 支持手动监控和Lambda监控两种方式
 */
//@Component
public class ChainLogManual {

    @Autowired
    private ChainLogProperties chainLogProperties;

    @Autowired(required = false)
    private List<ChainMethodCallback> callbacks;

    /**
     * 开始监控方法
     *
     * @param methodName 方法名
     * @return 监控会话对象
     */
    public ChainLogSession start(String methodName) {
        return start(methodName, null, null, null);
    }

    /**
     * 开始监控方法
     *
     * @param methodName 方法名
     * @param name       监控名称
     * @return 监控会话对象
     */
    public ChainLogSession start(String methodName, String name) {
        return start(methodName, name, null, null);
    }

    /**
     * 开始监控方法
     *
     * @param methodName 方法名
     * @param name       监控名称
     * @param desc       详细信息
     * @return 监控会话对象
     */
    public ChainLogSession start(String methodName, String name, String desc) {
        return start(methodName, name, desc, null);
    }

    /**
     * 开始监控方法
     *
     * @param methodName 方法名
     * @param name       监控名称
     * @param desc       详细信息
     * @param customs    自定义参数
     * @return 监控会话对象
     */
    public ChainLogSession start(String methodName, String name, String desc, Map<String, String> customs) {
        Date startTime = new Date();
        // 检查是否启用监控
        if (!chainLogProperties.isEnabled()) {
            return new DisabledChainLogSession();
        }

        // 获取当前监控上下文
        ChainApiLog chainApiLog = ChainLogContext.getChainApiLog();
        ChainMethodLog chainMethodLog = ChainLogContext.getCurrentChainMethodLog();

        // 创建链式监控信息，加入到现有的监控链中
        String parentId = null;
        if (chainMethodLog != null) {
            // 如果有父级链式监控，以父级链式监控为父节点
            parentId = chainMethodLog.getId();
        } else if (chainApiLog != null) {
            // 如果只有接口监控，以接口监控为父节点
            parentId = chainApiLog.getId();
        }

        ChainMethodLog chainInfo = createChainMonitorInfo(methodName, parentId, name, desc, customs, startTime);
        ChainLogContext.pushChainMethodLog(chainInfo);

        return new ActiveChainLogSession(chainInfo, chainApiLog, chainMethodLog);
    }

    /**
     * 创建链式监控信息
     */
    private ChainMethodLog createChainMonitorInfo(String methodName, String parentId, String name, String desc, Map<String, String> customs, Date startTime) {
        ChainMethodLog chainMethodLog = new ChainMethodLog(IdUtil.generateId(), parentId, startTime);

        // 基本信息
        chainMethodLog.setLevel(ChainLogContext.getCurrentLevel() + 1);
        chainMethodLog.setMethod(methodName);
        chainMethodLog.setClassName(getClassNameByMethodName(methodName));
        chainMethodLog.setName(name);
        chainMethodLog.setDesc(desc);
        chainMethodLog.setCustoms(customs);

        return chainMethodLog;
    }

    /**
     * 根据方法名获取类型
     *
     * @param methodName 方法名
     * @return 类名
     */
    private static String getClassNameByMethodName(String methodName) {
        int i = methodName.lastIndexOf(".");
        return methodName.substring(0, i);
    }

    /**
     * 完成链式监控信息
     */
    private void completeChainMonitorInfo(ChainMethodLog chainInfo) {
        Date endTime = new Date();
        chainInfo.setEndTime(endTime);
        chainInfo.setDuration(endTime.getTime() - chainInfo.getStartTime().getTime());
    }

    /**
     * 从方法引用中获取方法名
     */
    private String getMethodName(Serializable methodRef) {
        try {
            Method writeReplaceMethod = methodRef.getClass().getDeclaredMethod("writeReplace");
            writeReplaceMethod.setAccessible(true);
            SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(methodRef);

            String className = serializedLambda.getImplClass().replace('/', '.');
            String methodName = serializedLambda.getImplMethodName();

            return className + "." + methodName;
        } catch (Exception e) {
            // 如果无法获取方法名，返回默认值
            return "lambda.method";
        }
    }

    /**
     * 可序列化的Supplier接口
     */
    @FunctionalInterface
    public interface SerializableSupplier<T> extends Supplier<T>, Serializable {
    }

    /**
     * 可序列化的Function接口
     */
    @FunctionalInterface
    public interface SerializableFunction<T, R> extends Function<T, R>, Serializable {
    }

    private class ActiveChainLogSession implements ChainLogSession {

        private final ChainMethodLog chainInfo;
        private final ChainApiLog apiInfo;
        private final ChainMethodLog parentChainInfo;
        private boolean ended = false;

        public ActiveChainLogSession(ChainMethodLog curChainMethodLog, ChainApiLog chainApiLog,
                                     ChainMethodLog chainMethodLog) {
            this.chainInfo = curChainMethodLog;
            this.apiInfo = chainApiLog;
            this.parentChainInfo = chainMethodLog;
        }

        @Override
        public ChainLogSession withParams(Object... params) {
            if (!ended) {
                Map<String, Object> paramMap = ReflectionUtil.formatMethodParams(chainInfo.getMethod(), params);
                chainInfo.setParams(paramMap);
            }
            return this;
        }

        @Override
        public void endSuccess() {
            endSuccess(null);
        }

        @Override
        public void endSuccess(Object result) {
            if (ended) {
                return;
            }

            chainInfo.setSuccess(true);
            if (result != null) {
                chainInfo.setResult(result);
            }

            completeMonitoring(null);
        }

        @Override
        public void endException(Throwable exception) {
            endException(exception, null);
        }

        @Override
        public void endException(Throwable exception, Object result) {
            if (ended) {
                return;
            }

            chainInfo.setSuccess(false);
            if (exception != null) {
                chainInfo.setExceptionInfo(ExceptionUtil.getExceptionStackTrace(exception));
            }
            if (result != null) {
                chainInfo.setResult(result);
            }

            completeMonitoring(exception);
        }

        @Override
        public void close() {
            if (!ended) {
                endSuccess();
            }
        }

        /**
         * 完成监控
         */
        private void completeMonitoring(Throwable exception) {
            if (ended) {
                return;
            }

            ended = true;

            // 完成监控信息
            Date endTime = new Date();
            chainInfo.setEndTime(endTime);
            chainInfo.setDuration(endTime.getTime() - chainInfo.getStartTime().getTime());

            // 弹出当前监控信息
            ChainLogContext.popChainMethodLog();

            // 执行回调
            executeCallbacks(exception);
        }

        /**
         * 执行会话回调
         */
        private void executeCallbacks(Throwable exception) {
            if (callbacks == null || callbacks.isEmpty()) {
                return;
            }

            // 异步执行回调
            CompletableFuture.runAsync(() -> {
                for (ChainMethodCallback callback : callbacks) {
                    try {
                        if (exception != null) {
                            callback.onChainException(chainInfo, apiInfo, parentChainInfo, exception);
                        } else {
                            callback.onChainComplete(chainInfo, apiInfo, parentChainInfo);
                        }
                    } catch (Exception e) {
                        // 记录回调异常，但不影响主流程
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}